#include "sample.h"

namespace nil01 {
void main_func() { test_std_conditional(); }

void test_std_conditional() {
  typedef std::conditional<true, int, double>::type Type1;
  typedef std::conditional<false, int, double>::type Type2;
  typedef std::conditional<sizeof(int) >= sizeof(double), int, double>::type
      Type3;

  std::cout << typeid(Type1).name() << '\n';
  std::cout << typeid(Type2).name() << '\n';
  std::cout << typeid(Type3).name() << '\n';
}
}  // namespace nil01

namespace nil02 {

sample::sample() {}

void print() {}
template <typename T, typename... Types>
void print(T firstArg, const Types&... args) {
  std::cout << "T:" << firstArg << " ;";
  print(args...);
}

void test_varient_template() {
  std::cout << "hash code:" << std::hash<int>()(233) << std::endl
            << std::hash<long>()(22333L) << std::endl
            << std::hash<float>()(2.33) << std::endl
            << std::hash<char>()('a') << std::endl
            << std::hash<const char*>()("a") << std::endl
            << std::endl;
  print(std::hash<int>()(233), "\n", std::hash<int>()(23333L),

        "\n", std::hash<int>()(332233));

  std::tuple<int, int, int> t{1, 2, 3};
}

void test_vector(long& value) {
  std::cout << "\ntest_vector().........\n";
  std::vector<std::string> c;
  char buf[10];
  clock_t timeStart = clock();
  for (long i = 0; i < value; ++i) {
    try {
      std::snprintf(buf, 10, "%d", std::rand());
      c.push_back(std::string(buf));
    } catch (std::exception& p) {
      std::cout << "i=" << i << " " << p.what() << std::endl;
      std::abort();
    }
  }

  std::cout << "耗时：" << (clock() - timeStart) << std::endl;

  int a = 1;
  std::unique_ptr<int> pInt(&a);
  std::cout << *pInt;
  auto pInt2 = std::move(pInt);
  std::cout << "pInt:" << pInt;
  std::cout << "pInt2:" << pInt2 << std::endl;
  switch (a) {
    case 1:

      break;
    case 2:
      //;
      break;
    default:
        //
        ;
  }
}

}  // namespace nil02

void nil03::main_func() {
  //    unique_ptr_func();
  //    shared_ptr_func();
  check_shared_ptr();
}

void nil03::unique_ptr_func() {
  // (1)unique_ptr
  std::cout << "\n----unique_ptr----\n";
  std::unique_ptr<int> up1(new int(11));
  //  std::unique_ptr<int> up2(up2);  //不能通过编译

  std::cout << "*pu1 = " << *up1 << std::endl;

  std::unique_ptr<int> up3 = std::move(up1);  // unique_ptr支持 move

  std::cout << "up3=move(up1) --> *up3 = " << *up3 << "\n";
  std::cout << "up1 = " << up1 << "\n";  // up1已经被move释放，不可使用

  up3.reset();  //显示释放内存
  up1.reset();  // 不会导致运行时错误

  // unique_ptr 可以使用move操作来移走
  std::cout << "up1.reset();up1 = " << up1 << "\n";  // up1已经被释放，不可使用
  std::cout << "up3.reset();up3 = " << up3 << "\n";  // up3已经被释放，不可使用

  ;
}

void nil03::shared_ptr_func() {
  // (2)shared_ptr
  std::cout << "\n----shared_ptr----\n";
  std::shared_ptr<int> sp1(new int(12));
  std::shared_ptr<int> sp2 = sp1;

  std::cout << "shared_ptr<int> sp1(new int(12));"
               "\nshared_ptr<int> sp2 = sp1;\n";
  std::cout << "*sp1 = " << *sp1 << ", sp1 = " << sp1 << std::endl;
  std::cout << "*sp2 = " << *sp2 << ", sp2 = " << sp2 << std::endl;

  std::cout << "sp1 use_count=" << sp1.use_count() << std::endl;
  sp1.reset();
  std::cout << "sp1.reset();\nsp1.use_count=" << sp1.use_count() << "\n";
  std::cout << "sp2.use_count=" << sp2.use_count() << "\n";

  sp2.reset();
  std::cout << "sp2.reset();\nsp2.use_count=" << sp2.use_count() << "\n";
}

void nil03::check_shared_ptr() {
  std::shared_ptr<int> sp1(new int(22));
  auto sp2 = sp1;
  std::weak_ptr<int> wp = sp1;  // weak_ptr 指向 shared_ptr
  std::cout << "shared_ptr<int> sp1;\nauto sp2=sp1;\n";
  std::cout << "*sp1=" << *sp1 << "\n";
  std::cout << "*sp2=" << *sp2 << "\n";
  Check(wp);
  sp1.reset();
  std::cout << "sp1.reset();sp2=" << sp2 << std::endl;
  Check(wp);
  sp2.reset();
  std::cout << "sp2.reset();sp2=" << sp2 << std::endl;
  Check(wp);
}

void nil03::Check(std::weak_ptr<int>& wp) {
  std::cout << "Check(wp); wp.lock() =" << wp.lock() << std::endl;
  ;
  std::shared_ptr<int> sp = wp.lock();  // weak_ptr<int> 转换为 shared_ptr<int>
  if (sp != nullptr) {
    std::cout << "still *sp = " << *sp << std::endl;
  } else {
    std::cout << "pointer is invalid." << std::endl;
  }
}

namespace nil04 {

// old thread programing
const long long kBigNum = 100000000LL;
static long long total = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void* old_func(void* x) {
  std::cout << "x = " << x << std::endl;
  long long i;
  for (i = 0; i < kBigNum; ++i) {
    pthread_mutex_unlock(&m);
    total += i;
    pthread_mutex_unlock(&m);
  }
  return (void*)0;
}

void old_thread_func() {
  pthread_t t1, t2;
  if (pthread_create(&t1, NULL, &old_func, NULL)) {
    throw;
  }
  if (pthread_create(&t2, NULL, &old_func, NULL)) {
    throw;
  }

  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  std::cout << "thread ++ total= " << total << std::endl;
}

// C++11
std::atomic_llong total2{0};

void main_func() {
  //      cpp11_thread_func();
  cpp11_atomic_func();
}
void func(int) {
  for (long long i = 0; i < kBigNum; ++i) {
    total2 += i;
  }
}

void cpp11_thread_func() {
  std::thread t1(func, 0);
  std::thread t2(func, 0);

  t1.join();
  t2.join();

  std::cout << "total2=" << total2 << std::endl;
}

// atomic
std::atomic_flag lock = ATOMIC_FLAG_INIT;
void atomic_f(int n) {
  while (lock.test_and_set(std::memory_order_acquire))  // 尝试获得锁
  {
    std::cout << "Waiting from thread [" << n << "]" << std::endl;
  }
  std::cout << "Thread [" << n << "] starts working..." << std::endl;
}
void atomic_g(int n) {
  std::cout << "Thread [" << n << "] is going to start." << std::endl;
  lock.clear();
  std::cout << "Thread [" << n << "] starts working.\n";
}
void cpp11_atomic_func() {
  //  std::atomic<int> a{1};
  //  int b = a;
  lock.test_and_set();
  std::thread t1(atomic_f, 1);
  std::thread t2(atomic_g, 2);

  t1.join();
  usleep(1000);
  t2.join();
  //  std::atomic<int> b{a};  // atomic delete copy-ctor:implicitly-delete
}

}  // namespace nil04

namespace nil05 {
template <class T>
struct IteratorTraits {
  typedef std::bidirectional_iterator_tag iterator_category;
  typedef std::ptrdiff_t difference_type;
  typedef T value_type;
  typedef T* pointer;
  typedef T& reference;
};

template <typename T>
struct __ListNode {
  typedef void* void_pointer;
  void_pointer prev;
  void_pointer next;
  T data;
};

template <class T>
class List {
 protected:
  typedef __ListNode<T> list_node;

 public:
  typedef list_node* link_type;
  typedef typename IteratorTraits<T>::value_type value_type;

 private:
  link_type node;
};

template <class Arg, class Result>
struct UnaryFunction {
  typedef Arg argument_type;
  typedef Result result_type;
};

template <class Arg1, class Arg2, class Result>
struct BinaryFunction {
  typedef Arg1 first_argument_type;
  typedef Arg2 second_argument_type;
  typedef Result result_type;
};

template <class T>
struct Identity : public UnaryFunction<T, T> {
  const T& operator()(const T& x) const { return x; }
};

template <class T>
struct Less : public BinaryFunction<T, T, bool> {
  bool operator()(const T& x, const T& y) const { return x < y; }
};

void cpp11_array() {
  std::array<int, 10> a;
  std::cout << "sizeof(std::array<int,10>): " << sizeof(a) << "\n";
  std::vector<int> b;
  std::cout << "sizeof(std::vector<int>): " << sizeof(b) << "\n";
  using std::cout;
  using std::endl;
  cout << "Size of char : " << sizeof(char) << endl;
  cout << "Size of int : " << sizeof(int) << endl;
  cout << "Size of short int : " << sizeof(short int) << endl;
  cout << "Size of long int : " << sizeof(long int) << endl;
  cout << "Size of float : " << sizeof(float) << endl;
  cout << "Size of double : " << sizeof(double) << endl;
  cout << "Size of wchar_t : " << sizeof(wchar_t) << endl;

  cout << "sizeof(int*) = " << sizeof(int*) << endl;
  cout << "sizeof(int&) = " << sizeof(int&) << endl;

  cout << "Size of std::vector<int> : " << sizeof(std::vector<int>) << endl;
  cout << "Size of std::list<int> : " << sizeof(std::list<int>) << endl;
  cout << "Size of std::list<int> : " << sizeof(std::list<int>) << endl;
  cout << "Size of std::list<int*> : " << sizeof(std::list<int*>) << endl;

  cout << "Size of std::deque<int> : " << sizeof(std::deque<int>) << endl;
  cout << "Size of std::deque<int>::iterator : "
       << sizeof(std::deque<int>::iterator) << endl;
  cout << "Size of std::deque<int>::difference_type : "
       << sizeof(std::deque<int>::difference_type) << endl;
  cout << "Size of std::size_type : " << sizeof(std::size_t) << endl;  // 8

  //  std::list;
  int intA = 12;

  //  List<int>::iterator iter;

  IteratorTraits<int>::reference rA = intA;
  rA = 3;
  cout << "intA=" << intA << endl;
  cout << "sizeof(IteratorTraits<int>::reference) = "
       << sizeof(IteratorTraits<int>::reference) << endl;
  cout << "sizeof(IteratorTraits<int>::pointer) = "
       << sizeof(IteratorTraits<int>::pointer) << endl;
  ::nil01::main_func();
}

void cpp11_vector() {}

void cpp11_list() {}

void cpp11_forward_list() {}

void cpp11_deque() {}

void cpp11_stack() {}

void cpp11_queue() {}

void main_func() {
  // cpp11_array();
  auto x = Less<int>();
  int a = 3, b = 2;
  x(a, b);
  using std::cout;
  using std::endl;
  using std::map;
  cout << "Less<int>()(3,2) =" << endl;
}

void cpp11_array_sort() {
  std::array<int, 10> arr{12, 32, 34, 13, 50, -22, 103, 10, 25, 83};
  std::cout << "-----befor array sort---\n";
  auto print_func = [&arr]() {
    for (auto& elem : arr) {
      std::cout << elem << ", ";
    }
  };
  print_func();
  //  arr.data();
  std::sort(arr.begin(), arr.end(), [](int a, int b) { return b < a; });
  std::cout << "\n-----after array sort---\n";
  print_func();
  std::cout << "\n-----end array sort---\n";
}

#include <unordered_map>
void cpp11_unorderdmap() {
  std::unordered_map<int, std::string> u = {
      {1, "1"},  {2, "12"}, {13, "1"},  {23, "1"},
      {33, "1"}, {19, "1"}, {235, "1"}, {313, "1"},
  };
}

}  // namespace nil05
namespace nil06 {

int myfunc(int x, int y) { return x + 2 * y; }
struct myFunctor {
  int operator()(int x, int y) { return x + 3 * y; }
};

void main_func() {
  // using std::accumulate;
}

}  // namespace nil06
   // namespace nil05
